﻿namespace PINGStance

module SQLServer = 

    open BucketFunctions

    open System
    open System.Data
    open System.Data.SqlClient
    open System.Threading
    open System.Diagnostics

    let SQLTest( connection_string : string,
                 keep_alive_fire_mins : int,
                 report_at_ms : int,
                 sql_rate_secs : int, 
                 log_to_console : bool,
                 lock : System.Threading.ReaderWriterLock ) =


        //  Create two connections, one to check it stays alive (fire a query every 15 minutes) and the
        //  other for throughput - both connect once and reconnect on failure
        //  

        let stopWatch = new System.Diagnostics.Stopwatch()

        use conn_working = new SqlConnection()
        use conn_keepalive = new SqlConnection()
        use cmd = new SqlCommand()

        conn_working.ConnectionString <- connection_string
        conn_keepalive.ConnectionString <- connection_string

        let init_sql = "create table #t ( some_data varchar(max) not null );"
                        + "insert #t ( some_data ) values( replicate( '1234567890', 102 ) );"


        //  Do this forever until we get a signal to stop
        //
        let mutable msg = ""
        let mutable init_sql_conn = true

        //  Set Keep Alive Start Time
        let mutable keep_alive_time = DateTime.Now

        while 1 = 1 do

            if init_sql_conn then
                //
                //  Initialisation query
                //
                try
                    conn_working.Close()
                    conn_keepalive.Close()

                    conn_working.Open()
                    conn_keepalive.Open()

                    //  Create the SQL to use in the throghput test
                    cmd.Connection <- conn_working
                    cmd.CommandType <- CommandType.Text
                    cmd.CommandText <- init_sql
                    cmd.CommandTimeout <- 0

                    cmd.ExecuteNonQuery() |> ignore

                    keep_alive_time <- DateTime.Now
                    init_sql_conn <- false

                with
                    | _ as ex -> write_log_file( "SS", "Connection to SQL Failure: " + ex.Message, true, log_to_console, lock )
                                 Thread.Sleep( 15 * 1000 )  //  wait before trying again.
            
            if not init_sql_conn then
                //
                //  Throughput test
                //
                try
                    cmd.Connection <- conn_working
                    cmd.CommandType <- CommandType.Text
                    cmd.CommandText <- "select * from #t;"
                    cmd.CommandTimeout <- 0
            
                    stopWatch.Reset()
                    stopWatch.Start()

                    use reader = cmd.ExecuteReader()

                    stopWatch.Stop()

                    reader.Dispose()

                    if stopWatch.ElapsedMilliseconds >= int64 report_at_ms || report_at_ms = 0 then
                        msg <- "conn: working | dur_ms " + stopWatch.ElapsedMilliseconds.ToString()
                        write_log_file( "SS", msg, true, log_to_console, lock )

                    Thread.Sleep( int sql_rate_secs * 1000 )

                    //
                    //  Throughput test
                    //
                    if DateTime.Now >= keep_alive_time.AddMinutes( float keep_alive_fire_mins ) then
                        cmd.Connection <- conn_keepalive
                        cmd.CommandType <- CommandType.Text
                        cmd.CommandText <- "select getdate() as now"
                        cmd.CommandTimeout <- 0
                
                        use reader = cmd.ExecuteReader()

                        reader.Dispose()

                        keep_alive_time <- DateTime.Now

                with
                    | _ as ex -> write_log_file( "SS", "Connection to SQL Failure: " + ex.Message, true, log_to_console, lock )
                                 Thread.Sleep( 15 * 1000 )  //  wait before trying again.
                                 init_sql_conn <- true
            

        0   // Return Code


